package com.si.control;

import java.awt.Component;
import java.awt.TextField;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JMenu;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;

import com.si.control.action.IAction;
import com.si.control.action.FourLayCollageAction;
import com.si.control.action.PreservedCollageAction;
import com.si.control.action.RandomCollageAction;
import com.si.control.action.HiResAction;
import com.si.control.action.SearchAction;
import com.si.ui.IImageCanvas;
import com.si.ui.enumn.ECollageAlgorithm;
import com.si.ui.enumn.EControlPanel;
import com.si.ui.enumn.EPreviewPanel;
import com.si.ui.enumn.EMenuBar;

public class ControlHandler extends ActionHandler<EControlPanel> implements ItemListener, Runnable {

	private final ExecutorService executor;
	private final SearchCollageTask searchCollageTask;
	
	private volatile List<BufferedImage> searchResults;
	private ECollageAlgorithm lastAlgorithm;
	
	public ControlHandler(final Map<String, Component> components) {
		this.executor = Executors.newCachedThreadPool();
		this.searchCollageTask = new SearchCollageTask(components);
		Runtime.getRuntime().addShutdownHook(new Thread(this));
		this.lastAlgorithm = ECollageAlgorithm.RandomCollage;
	}

	@Override
	public void run() {
		this.executor.shutdown();
	}

	@Override
	protected EControlPanel parse(final String str) {
		return EControlPanel.valueOf(str);
	}

	@Override
	protected void handle(final EControlPanel command) {
		switch(command) {
		case Button_Search: this.executor.submit(this.searchCollageTask); break;
		case Button_HiRes:
			try {
				new HiResAction().perform(this.searchResults);
			} catch (Exception e) {
				e.printStackTrace();
			}
			break;
		}
	}

	@Override
	public void itemStateChanged(final ItemEvent e) {
		final ECollageAlgorithm algorithm = this.searchCollageTask.parseAlgorithm();
		if(algorithm == this.lastAlgorithm || this.searchCollageTask.isSearchEmpty()) return;
		this.lastAlgorithm = algorithm;
		try {
			this.searchCollageTask.composeSet(algorithm);
			this.searchCollageTask.bar.setString("Completed");
			this.searchCollageTask.bar.setValue(100);
		} catch (Exception e1) {
			e1.printStackTrace();
		}
	}
	
	private class SearchCollageTask implements Runnable {
		
		private final TextField field;
		private final JComboBox combo;
		private final JButton btnSearch;
		private final JButton btnHiRes;
		private final IImageCanvas canvas;
		private final JProgressBar bar;
		private final JMenu menuConfig;
		
		private final IAction<String, List<BufferedImage>> searchAction;
		private final IAction<List<BufferedImage>, BufferedImage> randomCollageAction;
		private final IAction<List<BufferedImage>, BufferedImage> preservedCollageAction;
		private final IAction<List<BufferedImage>, BufferedImage> fourLayCollageAction;
		
		private SearchCollageTask(final Map<String, Component> components) {
			this.field = (TextField)components.get(EControlPanel.TextField_Search.toString());
			this.combo = (JComboBox)components.get(EControlPanel.Combo_Algorithm.toString());
			this.btnSearch = (JButton)components.get(EControlPanel.Button_Search.toString());
			this.btnHiRes = (JButton)components.get(EControlPanel.Button_HiRes.toString());
			this.canvas = (IImageCanvas)components.get(EPreviewPanel.Canavas.toString());
			this.bar = (JProgressBar)components.get(EControlPanel.ProgressBar.toString());
			this.menuConfig = (JMenu)components.get(EMenuBar.ConfigMenu.toString());
			this.searchAction = new SearchAction(this.bar);
			this.randomCollageAction = new RandomCollageAction();
			this.preservedCollageAction = new PreservedCollageAction();
			this.fourLayCollageAction = new FourLayCollageAction();
		}

		@Override
		public void run() {
			this.setEnabled(false);
			this.btnHiRes.setEnabled(false);
			try {
				this.bar.setValue(0);
				final ECollageAlgorithm algorithm = this.parseAlgorithm();
				final String text = this.field.getText();
				if(algorithm == null || text == null || text.length() <= 0) return;
				searchResults = this.searchAction.perform(this.field.getText());
				this.composeSet(algorithm);
				this.bar.setString("Completed");
				this.bar.setValue(100);
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				this.setEnabled(true);
			}
		}
		
		private ECollageAlgorithm parseAlgorithm() {
			final Object selected = this.combo.getSelectedItem();
			if(selected == null) {
				JOptionPane.showMessageDialog(null, "Please select a valid collaging algorithm.");
				return null;
			}
			return (ECollageAlgorithm)selected;
		}
		
		private void composeSet(final ECollageAlgorithm algorithm) throws Exception {
			if(algorithm == null) throw new IllegalArgumentException("Null algorithm");
			this.bar.setValue(70);
			this.bar.setString("Composing images...");
			BufferedImage collage = null;
			switch(algorithm) {
			case RandomCollage: collage = this.randomCollageAction.perform(searchResults); break;
			case PreservedCollage: collage = this.preservedCollageAction.perform(searchResults); break;
			case FourLay: collage = this.fourLayCollageAction.perform(searchResults); break;
			default: throw new IllegalArgumentException("Unsupported algorithm: ".concat(algorithm.toString()));
			}
			this.canvas.setImage(collage);
			if(collage != null) this.btnHiRes.setEnabled(true);
			else this.btnHiRes.setEnabled(false);
		}
		
		private void setEnabled(final boolean value) {
			this.field.setEnabled(value);
			this.combo.setEnabled(value);
			this.btnSearch.setEnabled(value);
			this.menuConfig.setEnabled(value);
		}
		
		private boolean isSearchEmpty() {
			return (searchResults == null || searchResults.isEmpty());
		}
	}
}
